כמו כל נתון אחר שהמשתמש שולח לנו, לא נסתמך על כתובות אימייל. נצטרך לבדוק לא רק אם כתובת האימייל תקנית, אלא גם אם האימייל באמת קיים. PHP באה לעזרתנו, ומספקת מסנן מובנה לבדיקת תקינות אימייל. לפני שנראה איך להשתמש בו, ננסה לכתוב פונקציה כזאת בעצמנו.
תיקוף אימייל מתבצע בשני שלבים:
1. בדיקה שמבנה כתובת האימייל שנשלחה תקין (הכתובת מכילה שטרודל, דומיין וכו').
2. בדיקה שהאימייל הזה באמת קיים בטבע.
הפונקציה
function isValidEmail($mail)
{
if (strpos($mail, '@') === false) return false;
$host = explode("@",$mail); $mxarr = array();
$regexp = '/^[-!#$%&\'*+\\.\/0-9=?A-Z^_`{|}~]+@([-0-9A-Z]+\.)+([0-9A-Z]){2,4}$/i';
if (!preg_match($regexp, $mail)) return false;
if (!getmxrr($host[1],$mxarr)) return false;
return true;
}
{
if (strpos($mail, '@') === false) return false;
$host = explode("@",$mail); $mxarr = array();
$regexp = '/^[-!#$%&\'*+\\.\/0-9=?A-Z^_`{|}~]+@([-0-9A-Z]+\.)+([0-9A-Z]){2,4}$/i';
if (!preg_match($regexp, $mail)) return false;
if (!getmxrr($host[1],$mxarr)) return false;
return true;
}
כתובת האימייל תקינה?
כתובת אימייל תקינה מורכבת משלושה חלקים: שם, דומיין וסיומת הדומיין ([email protected]).
השם יכול להיות מורכב:
1. מאותיות אנגלית (גדולות וקטנות).
2. מספרות.
3. מנקודה - אם היא לא ראשונה ולא אחרונה, וגם לא מופיעה פעמיים ברצף.
4. מכל אחד מהתווים הבאים: ! # $ % & ' * + - / = ? ^ _ ` { | } ~
את הבדיקה הזו מבצע הביטוי הרגולרי בפונקציה למעלה, שתחזיר false עם כתובת האימייל לא תקינה.
נוותר גם על אימיילים לא קיימים
אימייל כמו [email protected] כנראה לא קיים בכלל, אבל תקין מבחינת התווים שיש בו, וסביר להניח שניתקל באחד כזה אצל הנרשמים לאתר. במקרה הזה באה לעזרתנו הפונקציה המובנית getmxrr, שבודקת אם יש MX Record - (Mail Exchanger Record) עבור הדומיין הזה.
מהן רשומות MX?
כאשר אנחנו שולחים אימייל ל[email protected], תוכנת האימייל שלנו בודקת לאן מוביל הדומיין example.com, כלומר לאיזו כתובת IP לשלוח את האימייל. אותו דבר עושה בעצם הדפדפן כאשר אנחנו גולשים לאתר כלשהו; לפי שם הדומיין הוא מגלה לאיזה שרת לשלוח את הבקשה.
ניתן להגדיר לכל דומיין יעדים שונים עבור שרת הדואר או שרת האינטרנט, ולכן לכל דומיין יש כמה רשומות שונות מסוגים שונים, וביחד הן נקראות DNS Records. יש רשומה שמנתבת דוא"ל, רשומה שמנתבת גלישה לאתר, שורה שאליה סתם מכניסים טקסט אודות הדומיין...
הפונקציה getmxrr
הפונקציה getmxrr בודקת האם יש לדומיין הנתון רשומת MX. אם היא קיימת, אזי הדואר שנשלך אל הדומיין הזה כנראה מגיע לאיפשהו; אם היא לא קיימת, אזי אין שרת דואר שאליו יגיע האימייל, או שדומיין כזה פשוט לא קיים. לכן אין סיבה בכלל לשלוח לשם את האימייל שלנו, ויכול להיות שזה רק יזיק לציוני הספאם שלנו.
לסיכום, בדיקת תקינות האימייל מסתפקת בשני שלבים: בדיקה האם פורמט האימייל תקין ואם יש מען בכתובת שנמסרה.
תיקוף באמצעות מסנן מובנה
הביטוי הרגולרי למעלה נראה לנו מושלם, אך הוא רחוק מזה; ישנם כללים מסובכים יותר מאלה שכתבנו. לאור זאת, אפשר ורצוי להחליף אותו במסנן מובנה שיבדוק את תקינותה של כתובת האימייל. הנה הפונקציה הסופית:
<?php
function isValidEmail($mail)
{
if (!filter_var($mail, FILTER_VALIDATE_EMAIL)) return false;
$host = explode("@",$mail); $mxarr = array();
if (!getmxrr($host[1], $mxarr)) return false;
return true;
}
isValidEmail('[email protected]'); // true
isValidEmail('[email protected]'); // false
function isValidEmail($mail)
{
if (!filter_var($mail, FILTER_VALIDATE_EMAIL)) return false;
$host = explode("@",$mail); $mxarr = array();
if (!getmxrr($host[1], $mxarr)) return false;
return true;
}
isValidEmail('[email protected]'); // true
isValidEmail('[email protected]'); // false
גם התיקוף הזה לא מושלם
קודם כול, לפי RFC 2821, כשאין רשומות MX ב-DNS (שזה מה שהפונקציה getmxrr בודקת), שם המארח עצמו אמור לשמש כ-MX היחיד. אותנו זה לא אמור לעניין, כי כל המשתמשים שלנו ישתמשו בשירות דוא"ל נורמלי מספיק כדי לספק רשומות MX ב-DNS.
אם זו לא בעיה, מה כן? ובכן, יכול להיות שכתובת האימייל תקינה, ושבאמת קיים אימייל כזה, אבל מי אמר שזה באמת האימייל הנכון? אולי המשתמש שלנו טעה בהקלדה? או אולי הוא הזין כתובת אימייל של מישהו אחר בכוונה (כי הוא ספאמר)? לכן נצטרך גם לשלוח אימייל אימות, שבו נבקש מהמשתמש ללחוץ על קישור הפעלה עם ערך רנדומלי ארוך, ועד שלא תישלח בקשה כזאת לאתר שלנו - המשתמש יהיה מוקפא. (מובן שנצטרך גם לעבוד עם בסיס נתונים.)
נערך לאחרונה ב-18.1.2014 על ידי אוראל.
תגובות לכתבה:
gfdh
יפה מאוד
תודה , זה עזר לי :)
מדריך לא כל כך טוב אין פרוט על כל פונקצייה
לא מובן =\
אין פה מה להבין. המטרה היא שתראה את הפונקציה, תלמד מהקוד שאפשר לבדוק לא רק האם האימייל נראה תקין מבחינה וויזואלית, אלה אפילו לבדוק אם הוא באמת קיים, לדוגמה
[email protected] קיים
[email protected] לא קיים
למרות שמבחינה תחבירית שניהם תקינים.
להסביר את התפקיד של הפונקציות הפנימיות זה עבודה של הדוקומנטציה, לא שלי. אם אין לך מושג מה עושה explode, filter_var, getmxrr - תפתח את הדוקומנטציה ותקרא.
הי אלכס,
מה שלומך?
שאתה מדבר על "בדיקה שהאימייל הזה באמת קיים בטבע",
אם אני מבין אותך נכון אתה מדבר אך ורק על צורה תחבירית ולא על קיום של כתובת מייל כמו [email protected]
שהיא לא קיימת נכון ?
גם בדיקה כזו הוא מבצע .
טוב לדעת.
תודה!
עוד יותר טוב לבדוק :)
מוזר...
חסר פה החלק של האם קיים כזה אימייל................
יש על זה 5 פסקאות שלמות עם הכותרת
נוותר גם על אימיילים לא קיימים: [email protected]
מה עדיף:
לעשות ביטוי מעצמי?
או להשתמש בפילטר הקיים?
אם עדיף פילטר - אפשר לראות את הביטוי שעומד מאחוריו?
כי אני משתמש בזה:
/^([a-zA-Z\d]+_?)+$/ - והבעייה היא שיש נקודה בהתחלה אז אפשר להכניס כל מיני סימנים לא רצויים
(מצד שני לשים הגבלה רק לאותיות ומספרים זה לא טוב כי יש ספקים שמשתמשים בסימנים נוספים
מה לעשות?
** הערה*
הביטוי הוא:
/.+@\w+(\.\w+)+$/
(משום מה האתר פה מראה את זה הפוך,אז תקראו את זה מימין לשמאל[מתחיל בנקודה)]
תמיד תשתמשו בפילטרים. הם מהירים יותר, חוסכים כאב ראש מיותר ועושים את העבודה כמו שצריך.
אני יחזק את מה ש ctulhu אמר.
את הביטוי מאחורי הפילטר אפשר לראות פה:
https://github.com/php/php-src/blob/master/ext/filter/logical_filters.c
שורה 525
+ למה אתה ממציא את האופניים? הפונקציה כתובה למעלה. קח ותשתמש.
זה הפונקצייה שבודקת אם קיים כזה אימייל?
או שבודקת את התחביר?
אם נשתמש בפונקציות אז הביטויים הרגולרים יוזנחו..לא כך?
המדריך כולל בערך 4 שורות פונקציה ועוד הרבה פיסקאות שמסבירות בדיוק מה היא עושה.
שזה גם בדיקה של תקינות תחבירית (עם ביטוי רגולרי או פילט, תלוי באיזה מהקוביות הכחולות אתה בוחר)
וגם קיימות רישום MX עבור אותה כתובת, כדי לבדוק שהיא הכן קיימת
ובקישור שהבאת(שחושף מה מאחורי הפילטר),זה נראה לי היה זאת שבודקת אם המייל קיים.(שורה 525)
ואני מחפש את הביטוי שמאחורי הפילטר שבודק תחביר של אימייל...
או שאני לא מבין אותך,
אני יעשה לך סדר. כדי לבדוק שאימייל כתוב גם בצורה תחבירית נכונה _וגם_ קיים - אתה לוקח את ארבעת השורות במלבן בכחול בסוף המדריך ומעתיק לקוד שלך. זהו.
הביטוי הרגולרי שעומד מאחורי הפילטר, *שבודק את _התחביר_*, נמצא בשורה 525.
המדריך לביטויים רגולריים באתר עשוי לעזור לך להבין את הביטוי ההוא.
זה הכל.
אשמח לדעת איך שורה כזאת,בודקת רק תחביר אימייל:
/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD
"צוטט משורה מס' 525"
אני יכול רק להמליץ לך על מדריך ביטויים רגולריים או אפילו ספר.
יש כללים מסוימים של תקינות כתובת אימייל, המתוארים במסמך שנקרא RFC 2822
(הקישור הראשון בגוגל לפי השם הזה)
הביטוי הרגולרי הזה בודק בדיוק את מה שכתוב במסמך הזה, לא פחות ולא יותר
לא הבנתי מילה.
שאני עושה ביטוי רגולרי (לתחביר אימייל)הוא נראה כך:
/.+@\w+(\.\w+)+$/
ממילא הפילטר שבודק תחביר אימייל צריך להיות דומה (פלוס מינוס)
אז למה זה כל השורות שהובא בהודעה קודמת??
**ואני מדבר רק עלתחביר אימייל.[ולא על 'קיים בטבע']
בקיצור:
איך נראה הביטוי הרגולרי "שמסתתר" מאחורי הפילטר FILTER_VALIDATE_EMAIL
[הבודק האם האימייל נכון מבחינה תחבירית]
זה הכל-
זה /.+@\w+(\.\w+)+$/ שטויות.
והביטוי בשורה 525 הוא הביטוי שבודק את כל הכללים המתאימים. למה הוא יותר ארוך מהביטוי שאתה הבאת? כי הביטוי שאתה הבאת לא בדוק עשירית מהכללים שחלים על תחביר של כתובת דואר אלקטרונית נכונה. למה הביטוי שאתה הבאת כזה גרוע אני לא מתכוון להסביר. יש כללים, RFC 2822, יש מדריך ביטויים רגולריים. כל השאר לבד.
2 דברים
א.[קצת באיחור אבל בכל זאת] רק תגיד בערך למה הביטוי שלי לא טוב בשביל לבדוק תחביר לאימייל(תנסה ותראה שזה עובד)
_*_*_*_**_*_*_*_*_**_*_*#_#*_*_#
ב.[וזה העיקרי] אז אני יכול להשתמש רק בפילטר שבודק אם האימייל קיים בטבע וזהו!(כי אם זה קיים בטבע אז ממילא זה תחביר נכון..:)
?
אין פילטר כזה שבודק "רק אם קיים בטבע". את זה עושה פונקציית ה MX וכל מה שהיא בודקת זה שקיים דומיין וקיימת לו רשומת MX. כלומר מבחינת גם [email protected] יעבור.
הפילטר הוא בסה"כ ביטוי רגולרי פנימי שמנוע ה PHP עושה, לא שום דבר אחר.
הפילטר לא יודע אם [email protected]
קיים או לא.
בגלל זה אתה צריך את שניהם.
למשל הביטוי שלך יעביר [email protected]
מה הבעייה להריץ את זה: FILTER_VALIDATE_EMAIL על אינפוט בעזרת filter_input??
ועוד משהו:
ברגע שיש בדיקה של אימייל קיים בטבע
אז אם הוא קיים ממילא הוא גם תקין...ואז הבדיקה התחבירית מיותרת
ואם הוא לא קיים אז לא!
ניסיתי את הקוד על האימייל שלי וזה מחזיר FALSE אחרי השורה:
$regexp = '/^[-!#$%&\'*+\\.\/0-9=?A-Z^_`{|}~]+@([-0-9A-Z]+\.)+([0-9A-Z]){2,4}$/i';
if (!preg_match($regexp, $mail)) return false;
בטוח שהקוד נכון?
כן. תצרף קישור לקוד ב phplive
http://phpguide.co.il/phplive?code=246
אני לא צריך קישור ל copy paste של הקוד ל phplive
אני צריך את הקוד שלא עובד לך.
http://phpguide.co.il/phplive?code=247
לא עדיף להשתמש בפילטר או בביטוי רגולרי??
יופי טופי
מהתיעוד של PHP לגבי getmxrr:
This function should not be used for the purposes of address verification. Only the mailexchangers found in DNS are returned, however, according to » RFC 2821 when no mail exchangers are listed, hostname itself should be used as the only mail exchanger with a priority of 0.
ממה שאני מבין כאן הפונקציה תחזיר לך שרתי mx במידה וקיימים כאלו ב-DNS אבל זה לא אומר שאם לא מוגדרים אז בהכרח לא קיים שרת מייל לדומיין, אלא המיילים ינותבו ל-hostname. מה דעתך?
שב 99.9999 אחוז מהמקרים זה כנראה אומר שאין שרת מייל לדומיין ואף אחד לא הולך לקבל את המייל הזה שנשלך ל .hostname
אם אני לא טועה, gmail אפילו לא שולח מיילים לדומיינים שאין להם mx ואתה מקבל הודעה על
mail delivery failure
מעולה, תודה
לא טוב
יכול להיות שבשרתים מסויימים הפונקציה האחרונה לא תעבוד?
העתקתי את הפונקציה אבל זה מדפיס לי שגיאה
Fatal error: Call to undefined function isValidEmailmail()
אשמח לעזרה תודה רבה ויום טוב
תודה זה יסתדר לי